<template>
  <view class="file-upload-component">
    <!-- 文件上传区域 -->
    <view class="upload-area" @click="chooseFile" v-if="!disabled">
      <view class="upload-content">
        <u-icon name="plus" size="40" color="#c0c4cc"></u-icon>
        <text class="upload-text">{{ tip }}</text>
        <text class="upload-hint">支持 {{ allowedTypes.join(', ') }} 格式，最大 {{ maxSize }}MB</text>
      </view>
    </view>

    <!-- 文件列表 -->
    <view class="file-list" v-if="fileList.length > 0">
      <view
        v-for="(file, index) in fileList"
        :key="file.uid || file.id || index"
        class="file-item"
      >
        <!-- 图片预览 -->
        <view v-if="isImageFile(file)" class="image-preview" @click="handleImageClick(file, index)">
          <image 
            :src="file.url || file.fileUrl" 
            class="preview-image"
            mode="aspectFill"
            @error="handleImageError"
          />
          <view class="image-overlay">
            <u-icon name="eye" size="20" color="#fff"></u-icon>
          </view>
        </view>
        
        <!-- 非图片文件图标 -->
        <view v-else class="file-icon" @click="handleFileClick(file)">
          <u-icon 
            :name="getFileIcon(file)" 
            size="32" 
            :color="getFileIconColor(file)"
          ></u-icon>
        </view>

        <!-- 文件信息 -->
        <view class="file-info">
          <text class="file-name">{{ file.name || file.fileName }}</text>
          <text class="file-size">{{ formatFileSize(file.size || file.fileSize) }}</text>
        </view>

        <!-- 操作按钮 -->
        <view class="file-actions">
          <u-button
            v-if="!disabled"
            type="error"
            size="mini"
            @click.stop="handleRemove(file, index)"
          >
            删除
          </u-button>
        </view>
      </view>
    </view>

    <!-- 上传进度 -->
    <view class="upload-progress" v-if="uploadProgress > 0 && uploadProgress < 100">
      <u-line-progress
        :percentage="uploadProgress"
        :show-text="true"
        :stroke-width="4"
        active-color="#2979ff"
      ></u-line-progress>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { mobileUser as mobileUserApi } from '@/api/user'

interface Props {
  uploadType?: string
  uploadSource?: string
  multiple?: boolean
  accept?: string
  modelValue?: any[]
  disabled?: boolean
  limit?: number
  tip?: string
  maxSize?: number
  allowedTypes?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  uploadType: 'OTHER',
  uploadSource: 'APP',
  multiple: false,
  accept: '*',
  disabled: false,
  limit: 10,
  tip: '点击上传文件',
  maxSize: 10,
  allowedTypes: () => ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'xls', 'xlsx']
})

const emit = defineEmits(['update:modelValue', 'on-success', 'on-error', 'on-file-click'])

const uploadProgress = ref(0)

const fileList = computed({
  get: () => props.modelValue || [],
  set: (value) => emit('update:modelValue', value)
})

// 选择文件
const chooseFile = () => {
  if (props.disabled) return
  
  uni.chooseFile({
    count: props.multiple ? props.limit : 1,
    type: 'all',
    extension: props.allowedTypes,
    success: (res) => {
      const files = res.tempFiles
      files.forEach(file => {
        uploadSingleFile(file)
      })
    },
    fail: (err) => {
      console.error('选择文件失败:', err)
      uni.showToast({
        title: '选择文件失败',
        icon: 'none'
      })
    }
  })
}

// 上传单个文件
const uploadSingleFile = async (file: any) => {
  try {
    uploadProgress.value = 0

    // 验证文件大小
    if (file.size > props.maxSize * 1024 * 1024) {
      uni.showToast({
        title: `文件大小不能超过 ${props.maxSize}MB`,
        icon: 'none'
      })
      return
    }

    // 验证文件类型
    const fileExt = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase()
    if (!props.allowedTypes.includes(fileExt)) {
      uni.showToast({
        title: `不支持的文件类型: ${fileExt}`,
        icon: 'none'
      })
      return
    }

    // 上传文件
    const response = await mobileUserApi.uploadFile(file, props.uploadType, props.uploadSource)
    
    if (response.code === 200) {
      uploadProgress.value = 100
      
      const uploadedFile = {
        ...file,
        id: response.data.id,
        fileName: response.data.fileName,
        fileSize: response.data.fileSize,
        fileUrl: response.data.fileUrl,
        url: response.data.fileUrl,
        status: 'success'
      }
      
      addFileToList(uploadedFile)
      emit('on-success', response, uploadedFile, fileList.value)
      
      uni.showToast({
        title: '上传成功',
        icon: 'success'
      })
    } else {
      throw new Error(response.message || '上传失败')
    }
  } catch (error) {
    uploadProgress.value = 100
    
          console.error('文件上传失败:', error)
      emit('on-error', error, file, fileList.value)
    
    uni.showToast({
      title: '上传失败',
      icon: 'none'
    })
  } finally {
    setTimeout(() => {
      uploadProgress.value = 0
    }, 2000)
  }
}

// 添加文件到列表
const addFileToList = (file: any) => {
  const newFileList = [...fileList.value]
  newFileList.push(file)
  emit('update:modelValue', newFileList)
}

// 删除文件
const handleRemove = (file: any, index?: number) => {
  uni.showModal({
    title: '提示',
    content: '确定要删除这个文件吗？',
    success: (res) => {
      if (res.confirm) {
        const newFileList = [...fileList.value]
        const removeIndex = index !== undefined ? index : newFileList.findIndex(f => f.uid === file.uid || f.id === file.id)
        if (removeIndex > -1) {
          newFileList.splice(removeIndex, 1)
          emit('update:modelValue', newFileList)
        }
      }
    }
  })
}

// 点击文件
const handleFileClick = (file: any) => {
  emit('on-file-click', file)
  const previewUrl = (file as any).url || (file as any).fileUrl
  if (previewUrl) {
    // 如果是图片，预览图片
    if (isImage(file)) {
      uni.previewImage({
        urls: [previewUrl],
        current: previewUrl
      })
    } else {
      // 其他文件类型，下载
      uni.downloadFile({
        url: previewUrl,
        success: (res) => {
          if (res.statusCode === 200) {
            uni.openDocument({
              filePath: res.tempFilePath
            })
          }
        }
      })
    }
  }
}

// 图片预览
const handleImageClick = (file: any, index: number) => {
  const previewUrl = file.url || file.fileUrl
  if (previewUrl) {
    uni.previewImage({
      urls: [previewUrl],
      current: previewUrl
    })
  }
}

// 图片加载失败
const handleImageError = (e: any) => {
  console.error('图片加载失败:', e)
}

// 判断是否为图片文件
const isImageFile = (file: any) => {
  const fileName = file.name || file.fileName || ''
  const ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
  return ['jpg', 'jpeg', 'png', 'gif'].includes(ext)
}

// 获取文件图标
const getFileIcon = (file: any) => {
  const fileName = file.name || file.fileName || ''
  const ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
  
  const iconMap: Record<string, string> = {
    jpg: 'photo',
    jpeg: 'photo',
    png: 'photo',
    gif: 'photo',
    pdf: 'file-text',
    doc: 'file-text',
    docx: 'file-text',
    xls: 'file-text',
    xlsx: 'file-text'
  }
  
  return iconMap[ext] || 'file'
}

// 获取文件图标颜色
const getFileIconColor = (file: any) => {
  const fileName = file.name || file.fileName || ''
  const ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
  
  const colorMap: Record<string, string> = {
    jpg: '#19be6b',
    jpeg: '#19be6b',
    png: '#19be6b',
    gif: '#19be6b',
    pdf: '#fa3534',
    doc: '#2979ff',
    docx: '#2979ff',
    xls: '#ff9900',
    xlsx: '#ff9900'
  }
  
  return colorMap[ext] || '#909399'
}

// 判断是否为图片
const isImage = (file: any) => {
  const fileName = file.name || file.fileName || ''
  const ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
  return ['jpg', 'jpeg', 'png', 'gif'].includes(ext)
}

// 格式化文件大小
const formatFileSize = (size: number) => {
  if (!size) return '0 B'
  
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let unitIndex = 0
  let fileSize = size
  
  while (fileSize >= 1024 && unitIndex < units.length - 1) {
    fileSize /= 1024
    unitIndex++
  }
  
  return `${fileSize.toFixed(2)} ${units[unitIndex]}`
}

// 清空文件列表
const clearFiles = () => {
  emit('update:modelValue', [])
}

// 暴露方法
defineExpose({
  clearFiles,
  chooseFile
})
</script>

<style lang="scss" scoped>
.file-upload-component {
  .upload-area {
    width: 100%;
    min-height: 160rpx;
    border: 2rpx dashed #d9d9d9;
    border-radius: 8rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fafafa;
    transition: all 0.3s;
    padding: 20rpx;

    &:active {
      border-color: #2979ff;
      background-color: #f0f8ff;
    }

    .upload-content {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text-align: center;

      .upload-text {
        font-size: 28rpx;
        color: #606266;
        margin-top: 16rpx;
        line-height: 1.4;
        word-break: break-word;
      }

      .upload-hint {
        font-size: 24rpx;
        color: #909399;
        margin-top: 8rpx;
        line-height: 1.3;
        word-break: break-word;
      }
    }
  }

  .file-list {
    margin-top: 24rpx;

    .file-item {
      display: flex;
      align-items: center;
      padding: 24rpx;
      border: 1rpx solid #e4e7ed;
      border-radius: 8rpx;
      margin-bottom: 16rpx;
      background-color: #ffffff;

      .image-preview {
        position: relative;
        width: 80rpx;
        height: 80rpx;
        border-radius: 8rpx;
        overflow: hidden;
        margin-right: 24rpx;

        .preview-image {
          width: 100%;
          height: 100%;
          object-fit: cover;
        }

        .image-overlay {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background-color: rgba(0, 0, 0, 0.5);
          border-radius: 8rpx;
          display: flex;
          align-items: center;
          justify-content: center;
          opacity: 0;
          transition: opacity 0.3s;

          &:active {
            opacity: 1;
          }
        }
      }

      .file-icon {
        margin-right: 24rpx;
      }

      .file-info {
        flex: 1;
        min-width: 0;

        .file-name {
          font-size: 28rpx;
          color: #303133;
          margin-bottom: 8rpx;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          display: block;
        }

        .file-size {
          font-size: 24rpx;
          color: #909399;
          display: block;
        }
      }

      .file-actions {
        display: flex;
        gap: 16rpx;
      }
    }
  }

  .upload-progress {
    margin-top: 24rpx;
  }
}
</style> 